home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cocktail / doc.lha / doc.doc / rex.doc < prev    next >
Text File  |  1992-09-25  |  91KB  |  2,839 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11. ___________________________________________________________________
  12.  
  13.  
  14.                                    Rex
  15.                                    A Scanner Generator
  16.  
  17.                                    J. Grosch
  18.  
  19.  
  20. ___________________________________________________________________
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50. ___________________________________________________________________
  51.                                    GESELLSCHAFT FUeR MATHEMATIK
  52.                                    UND DATENVERARBEITUNG MBH
  53.  
  54.                                    FORSCHUNGSSTELLE FUeR
  55.                                    PROGRAMMSTRUKTUREN
  56.                                    AN DER UNIVERSITAeT KARLSRUHE
  57. ___________________________________________________________________
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.                                    Project
  76.  
  77.                              Compiler Generation
  78.  
  79.          ___________________________________________________________
  80.  
  81.                           Rex - A Scanner Generator
  82.  
  83.  
  84.                                  Josef Grosch
  85.  
  86.  
  87.                                 July 31, 1992
  88.  
  89.          ___________________________________________________________
  90.  
  91.  
  92.                                  Report No. 5
  93.  
  94.  
  95.                              Copyright c 1992 GMD
  96.  
  97.  
  98.             Gesellschaft fuer Mathematik und Datenverarbeitung mbH
  99.                 Forschungsstelle an der Universitaet Karlsruhe
  100.                           Vincenz-Priesznitz-Str. 1
  101.                                D-7500 Karlsruhe
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.                                      Rex                                     1
  135.  
  136.  
  137. 1.  Introduction
  138.  
  139.      Rex generates programs to be used in lexical analysis of text. A  typical
  140. application is the generation of scanners for compilers.  Rex stands for Regu-
  141. lar EXpression tool. In principle it is a remake of LEX [Les75].
  142.  
  143.      Rex processes  a  specification  containing  regular  expressions  to  be
  144. searched for, and actions written in C or Modula-2 to be executed when expres-
  145. sions are found. Unrecognized portions of the input are copied by  default  to
  146. standard output.  Rex generates a table-driven scanner consisting of a scanner
  147. routine and control tables. The scanner routine implements a tunnel  automaton
  148. [Gro89] and contains a copy of the specified actions.
  149.  
  150.      The scanners generated by Rex are 5  times  faster  and  up  to  5  times
  151. smaller  than  those  generated  by  LEX.  It  is possible to reach a speed of
  152. 180,000 to 195,000 lines per minute on a MC 68020 processor  (including  input
  153. from  file).  If hashing of identifiers is performed additionally the speed is
  154. between 125,000 and 150,000 lines per minute.  The generator Rex itself is  10
  155. to  20  times  faster  than  LEX  in typical cases.  Like LEX, Rex has all the
  156. features necessary to scan contemporary languages: that is the  left  and  the
  157. right  context can be taken into account to identify a token. The left context
  158. is handled by so-called start states and the right context by additional regu-
  159. lar  expressions.   The  source coordinates (line and column number) of recog-
  160. nized words are calculated automatically. Scanners can  be  generated  in  the
  161. languages C and Modula-2. Rex itself is implemented in Modula-2.
  162.  
  163.      The following chapters constitute the user  manual  of  Rex.   Chapter  2
  164. gives  an  overview  of  the  operation  of  Rex  and  how its output is to be
  165. integrated  in  e.  g.  compilers.   Chapter  3  describes  the  specification
  166. language.   Chapter  4  summarizes  the  predefined items of the specification
  167. language.  Chapter 5 contains the specification of the interface of  the  gen-
  168. erated  scanners.   Chapter 6 shows how to invoke and use Rex.  Chapter 7 con-
  169. tains some details of the implementation.  Chapter 8 describes the differences
  170. between  Rex and LEX for those already familiar with LEX.  The appendices con-
  171. tain a grammar for the input language and some examples.
  172.  
  173. 2.  Overview
  174.  
  175.      Figure 1 gives an overview of the observable behaviour of Rex.  It  takes
  176. as  input  a  specification  of  a  lexical  analyser  written in the language
  177. described in the next chapter. The output is the source text of a scanner  and
  178. scanner tables (in case of Modula-2). The source text consists of a specifica-
  179. tion and a body part. These parts are files with the suffixes 'h' and 'c' if C
  180. is the target language. In the case of Modula-2 the parts are a definition and
  181. an implementation module.  The scanner requires a source module to get  blocks
  182. of  characters  e. g. by input from file. Rex can be asked to provide a proto-
  183. type source module which performs input from the  UNIX  standard  input  file.
  184. Additionally  Rex  can  be  asked  to  provide a main program to serve as test
  185.  
  186.  
  187.                              Fig. 1: Rex Overview
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.                                      Rex                                     2
  200.  
  201.  
  202. driver of the scanner. This main program calls the scanner routine  until  the
  203. end of the input is reached.
  204.  
  205.      The above mentioned source programs constitute the minimum  configuration
  206. to  run  the generated scanner. What is happening after the compilation of the
  207. program modules is shown in the "run time" half of Fig. 1. During  initializa-
  208. tion  the  scanner  reads its tables from a file (in case of Modula-2 - C uses
  209. initialized arrays).  Then the scanner driver starts calling the scanner  rou-
  210. tine  which  in turn sometimes calls the source module routines to get charac-
  211. ters. The data flow is in the opposite direction. The  source  module  returns
  212. blocks  of  characters  to  the  scanner.  The  scanner analyzes the character
  213. stream, executes the  associated  actions  upon  finding  character  sequences
  214. matched  by  regular expressions, and eventually returns tokens to the scanner
  215. driver. In general the scanner driver can be replaced by any other  main  pro-
  216. gram or subroutine like e. g. a parser.
  217.  
  218. 3.  Specification Language
  219.  
  220.      The input of Rex consists of 3 parts:
  221.  
  222. - code written in the target language to be copied unchanged to the output (see 3.7.)
  223. - definitions of named regular expressions and start states (see 3.4. + 3.5.)
  224. - a set of regular expressions with associated actions written in the target language (see 3.2.)
  225.  
  226. The first two parts are optional. We discuss the three parts in reverse  order
  227. after introducing some lexical conventions.
  228.  
  229. 3.1.  Lexical Conventions
  230.  
  231.      The specification can be written in unformatted manner. That means  white
  232. space  in  the  form  of blanks, tab characters, and newline characters has no
  233. meaning except to separate other items.  Comments are written in the style  of
  234. C: text included in '/*' and '*/' is ignored. Comments may not be nested.  The
  235. specification uses a few keywords which should be escaped if needed  as  iden-
  236. tifiers (see below):
  237.  
  238.     BEGIN         CLOSE         DEFAULT       DEFINE        EOF
  239.     EXPORT        GLOBAL        LOCAL         NOT           RULE
  240.     RULES         SCANNER       START
  241.  
  242. The following special characters are used as operators, delimiters, or  escape
  243. characters:
  244.  
  245.     =  .  ,  :  :-  "  #  +  -  *  /  |  ?  (  )  [  ]  {  }  <  >  \
  246.  
  247.  
  248.      Besides keywords and the above special characters a scanner specification
  249. is composed of characters, numbers, identifiers, strings, and actions.
  250.  
  251.      A character denotes itself. Special characters have to be escaped using a
  252. preceding  escape  character.  The  escape character is a backslash: '\'.  For
  253. certain non-graphic characters the same escape sequences as in C are possible:
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.                                      Rex                                     3
  265.  
  266.  
  267.                           newline           NL   \n
  268.                           horizontal tab    HT   \t
  269.                           vertical tab      VT   \v
  270.                           backspace         BS   \b
  271.                           carriage return   CR   \r
  272.                           form feed         FF   \f
  273.  
  274.  
  275. Other unprintable characters are represented by the escape character  followed
  276. by an integer decimal number giving the internal coding.
  277.  
  278.     ;  \+  \\  \n  \10
  279.  
  280.  
  281.      Numbers denote numerical integer values. They consist of  a  sequence  of
  282. digits.
  283.  
  284.     8  12  0
  285.  
  286.  
  287.      Identifiers are used to refer to named entities. They consist of a letter
  288. followed  by letters, digits, or underscore characters '_'. Lower case as well
  289. as upper case letters are possible. If an identifier is not defined its  char-
  290. acter  sequence  is treated as a string. Identifiers that are keywords have to
  291. be escaped by a preceding escape character.
  292.  
  293.     letter  HexDigit  under_score  \BEGIN  END
  294.  
  295.  
  296.      Strings denote a sequence of characters. They consist of  a  sequence  of
  297. characters enclosed in double quotes '"'. It is not possible to include a dou-
  298. ble quote or an newline character into a string. No escape  is  needed  within
  299. strings. It is a shorthand for escaping a whole sequence of characters.
  300.  
  301.     "BEGIN"  ":="  "\"
  302.  
  303.  
  304.      Actions are statements to be copied unchanged into  the  generated  code.
  305. The statements have to be written in the desired target language.  The actions
  306. have to be enclosed in braces '{' '}'.  The characters '{' and '}' can be used
  307. within  the actions as long as they are either properly nested or contained in
  308. strings or in character constants.  Otherwise they have to  be  escaped  by  a
  309. backslash  character '\'. The escape character '\' has to be escaped by itself
  310. if it is used outside of strings or character constants: '\\'. In  general,  a
  311. backslash character `\` can be used to escape any character outside of strings
  312. or character constants. Within those tokens the escape  conventions  are  dis-
  313. abled  and  the  tokens are left unchanged.  There are additionally statements
  314. available to aid in scanning (see section 4.4.).
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.                                      Rex                                     4
  330.  
  331.  
  332.     { printf ("BEGIN recognized\n"); }
  333.     { return SymBegin; }
  334.     { if (level > 0) { GetWord (String); Concatenate (Word, String); } }
  335.     { printf ("} recognized\n"); }
  336.  
  337.  
  338. 3.2.  Regular Expressions
  339.  
  340.      In general the specification of a scanner consists of the keyword RULE or
  341. RULES  followed  by  a list of regular expressions each one associated with an
  342. action.
  343.  
  344.     RULE
  345.     BEGIN   : { printf ("BEGIN recognized"); }
  346.     END     : { printf ("END   recognized"); }
  347.     ;       : { printf (";     recognized"); }
  348.  
  349. The scanner generated from the above  example  specification  would  print  an
  350. appropriate  message  upon  finding  one  of  the character sequences 'BEGIN',
  351. 'END', or ';' in the input whenever they appear. We say a  character  sequence
  352. and  a  regular  expression  match  if  the character sequence has a structure
  353. according to the regular expression.
  354.  
  355.      In general the input of the scanner is searched for  character  sequences
  356. which match one of the specified regular expressions and the associated action
  357. is executed. Input characters which are not matched by any regular  expression
  358. are copied by default to standard output.
  359.  
  360.      The syntax to write regular expressions is as follows (see Appendix 1 for
  361. a  complete definition of the syntax). The productions are given in increasing
  362. precedence:
  363.  
  364.     Reg_Expr: Reg_Expr '|' Reg_Expr
  365.             | Reg_Expr Reg_Expr
  366.             | Reg_Expr '+'
  367.             | Reg_Expr '*'
  368.             | Reg_Expr '?'
  369.             | Reg_Expr '[' Number ']'
  370.             | Reg_Expr '[' Number '-' Number ']'
  371.             | '(' Reg_Expr ')'
  372.             | Character_Set
  373.             | Character
  374.             | Identifier
  375.             | String
  376.             .
  377.  
  378.  
  379. -    A character is matched by a single identical character.
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.                                      Rex                                     5
  395.  
  396.  
  397.          a               matches the character 'a'
  398.          \t              matches a tab character
  399.          \n              matches a newline character
  400.          \10             matches a newline character (only if ASCII is used)
  401.          \\              matches the character '\'
  402.  
  403.  
  404. -    A string is matched by a character sequence identical to  the  characters
  405.      that make up the string.
  406.  
  407.          ":="            matches the character sequence ':='
  408.          "\"             matches the character '\'
  409.  
  410.  
  411. -    An identifier may be defined to refer to a regular  expression.  In  this
  412.      case  it  matches the same characters as the regular expression. An unde-
  413.      fined identifier is treated like a string, it matches its  own  character
  414.      sequence.
  415.  
  416.          END             matches the character sequence 'END'
  417.          \NOT            matches the character sequence 'NOT'
  418.  
  419.  
  420. -    A number is treated like a string, it matches its own character sequence.
  421.  
  422.          007             matches the character sequence '007'
  423.  
  424.  
  425. -    A character set matches one arbitrary character contained in the set.  It
  426.      is  written as a sequence of characters enclosed in braces. Ranges may be
  427.      used to include intervals of characters. The same  escapes  as  described
  428.      for characters may be used. Unprintable characters and the following ones
  429.      have to be escaped within character sets:
  430.  
  431.           '-'  '}'  ' '  '\'
  432.  
  433.      The predefined identifier ANY stands for a character set containing every
  434.      character  except  the newline character.  If a character set is preceded
  435.      by the operator '-' it matches one arbitrary character  except  the  ones
  436.      contained in the set.
  437.  
  438.          { +\-*/ }       matches the arithmetic operators + - * /
  439.          { A-Z a-z 0-9 } matches all letters and digits
  440.          - { \n }        matches all characters except the newline character
  441.          ANY             matches all characters except the newline character
  442.  
  443.  
  444. -    Two regular expressions separated by the operator  '|'  match  characters
  445.      that are matched by the first or by the second regular expressions.
  446.  
  447.          a | b           matches the characters 'a' or 'b'
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.                                      Rex                                     6
  460.  
  461.  
  462. -    Two regular expressions following each other with no operator in  between
  463.      match the concatenation of character sequences matched by the single reg-
  464.      ular expressions.
  465.  
  466.          a b             matches the character sequence 'ab'
  467.  
  468.  
  469. -    The operator '?' matches a character sequence matched  by  the  preceding
  470.      regular  expression or the empty character sequence.  In other words, the
  471.      specified characters are optional.
  472.  
  473.          a b ?           matches the character sequences 'a' and 'ab'
  474.  
  475.  
  476. -    The operator '+' matches a character sequence which can be matched by the
  477.      repetition of the preceding regular expression 1 or more times.
  478.  
  479.          a +             matches the character sequences 'a', 'aa', 'aaa', ...
  480.  
  481.  
  482. -    The operator '*' matches a character sequence which can be matched by the
  483.      repetition of the preceding regular expression zero or more times.
  484.  
  485.          a b *           matches the character sequences 'a', 'ab', 'abb',
  486.                          'abbb', ...
  487.  
  488.  
  489. -    A regular expression followed by a number in brackets matches a character
  490.      sequence  which can be matched by the repetition of the preceding regular
  491.      expression exactly the times specified by the number.
  492.  
  493.          a [4]           matches the character sequence 'aaaa'
  494.  
  495.  
  496. -    A regular expression followed by a range in brackets matches a  character
  497.      sequence  which can be matched by the repetition of the preceding regular
  498.      expression a number of times lying in between of the two given numbers.
  499.  
  500.          a [2-4]         matches the character sequences 'aa', 'aaa', and 'aaaa'
  501.  
  502.  
  503. -    Parentheses '(' ')' can be used for  grouping  in  more  complex  regular
  504.      expressions.
  505.  
  506.          (a | b+)? (c d)*matches strings like 'acdcd', 'cdcdcd', 'bcd', or 'bbb';
  507.                          but not 'ab', 'abb', or 'abcd'.
  508.  
  509.  
  510.      A complete regular expression which is not  part  of  any  other  regular
  511. expression  is  called a pattern. A pattern is matched exactly in the same way
  512. as regular expressions. It can be augmented by the following specifications.
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.                                      Rex                                     7
  525.  
  526.  
  527. -    A pattern preceded by the operator '<' matches a character sequence  only
  528.      if it appears at the beginning of a line.
  529.  
  530.          < {a-z} +       matches identifiers only at the beginning of lines
  531.  
  532.  
  533. -    A pattern followed by the operator '>' matches a character sequence  only
  534.      if it appears at the end of a line.
  535.  
  536.          " " + >         matches trailing spaces
  537.          < C ANY * >     matches FORTRAN comment lines
  538.  
  539.  
  540. -    A pattern followed by the operator '/' and a regular expression matches a
  541.      character sequence only if it is followed by a character sequence that is
  542.      matched by the regular expression behind the operator '/'.
  543.  
  544.          {0-9} + / ".."  matches numbers, but only if followed by two dots
  545.  
  546.  
  547. -    Several patterns that share a common action  can  be  given  in  a  comma
  548.      separated list, thus the action has to be specified only once.
  549.  
  550.           ' - {\n'} * ', \" - {\n"} * \"
  551.                          matches both possible forms of Modula-2 strings
  552.  
  553.  
  554. 3.3.  Ambiguous Specifications
  555.  
  556.      Rex can handle ambiguous specifications. When more  than  one  expression
  557. can match the current input, Rex chooses as follows:
  558.  
  559. -    The longest match is preferred.
  560.  
  561. -    Among rules which match the same number of  characters,  the  rule  given
  562.      first is preferred.
  563.  
  564.      The length of a match is the number of matched characters plus the number
  565. of  characters matched by the regular expression following the "right context"
  566. operator '/' if applicable.
  567.  
  568.     Example:
  569.     {0-9} + / ".."      : { return SymDecimal; }
  570.     {0-9} + "." {0-9} * : { return SymReal   ; }
  571.     ".."                : { return SymRange  ; }
  572.     "."                 : { return SymDot    ; }
  573.  
  574.  
  575.      Suppose the right context of the first rule above is missing. The input
  576.  
  577.     1..
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.                                      Rex                                     8
  590.  
  591.  
  592. would be recognized as SymReal and SymDot because SymReal matches two  charac-
  593. ters.  To get the right solution the right context is necessary. Now the input
  594. is recognized as SymDecimal and SymRange because SymDecimal matches 3  charac-
  595. ters.
  596.  
  597.     Example:
  598.     BEGIN   : { return SymBegin; }
  599.     END     : { return SymEnd  ; }
  600.     {A-Z} + : { return SymIdent; }
  601.  
  602.  
  603.      The rules for keywords should be given before the rule  for  identifiers.
  604. Otherwise the keywords would be recognized as identifiers.
  605.  
  606. 3.4.  Definitions
  607.  
  608.      Regular expressions can be given names. This serves to avoid  duplication
  609. of regular expressions or to increase the expressive power of a specification.
  610. After the keyword DEFINE a list of identifiers can be associated with  regular
  611. expressions.  Defined  identifiers  appearing  within  regular expressions are
  612. replaced by the regular expression given in the definition.   Undefined  iden-
  613. tifiers are treated as strings.  The identifier ANY is predefined to match any
  614. character except newline.
  615.  
  616.     Example:
  617.     letter           = { A-Z a-z } .
  618.     digit            = { 0-9 }     .
  619.     string_character = - { " \n }  .
  620.     ANY              = - { \n }    .
  621.  
  622.  
  623. 3.5.  Start States
  624.  
  625.      For complex tasks Rex offers a facility called  "start  states".  Usually
  626. the  generated  scanner  is  always  in  the standard state called STD and all
  627. specified patterns are recognized. In general the scanner is allowed to change
  628. its state between an arbitrary number of user defined states. The patterns can
  629. be specified to be recognized only in certain states.  Initially  the  scanner
  630. is  in  the  standard start state STD.  There are special statements to change
  631. the state of the scanner (see section 4.4.).  They can be used in the  actions
  632. of the rules.
  633.  
  634.      Start states have to be defined by giving a list of identifiers after the
  635. keyword START. The identifiers may be separated by commas.  The standard state
  636. STD is predefined.
  637.  
  638. -    A pattern without given start states is recognized in every  start  state
  639.      the scanner is in.
  640.  
  641. -    A pattern preceded by a list of start states (inclosed in '#' characters)
  642.      is  recognized  only if the scanner is in one of the listed start states.
  643.      Again the listed start states may be separated by commas.
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.                                      Rex                                     9
  655.  
  656.  
  657. -    A pattern preceded by  the  keyword  NOT  and  a  list  of  start  states
  658.      (enclosed  in  '#'  characters) is recognized only if the scanner is in a
  659.      start state not listed.
  660.  
  661.     Example:
  662.     START comment
  663.     RULE
  664.                "(*"         : {++ level; yyStart (comment);}
  665.     #comment#  "*)"         : {-- level; if (level == 0) yyStart (STD);}
  666.     #comment#  "(" | "*" | - {*(} + : {}
  667.     #STD#      {0-9} +      : {return SymNumber;}
  668.  
  669.  
  670.      The above example shows how to  handle  nested  comments  in  a  Modula-2
  671. scanner.   The  rule for opening comment brackets is recognized in all states.
  672. The nesting level is increased and we change the start state to  comment  with
  673. the predefined statement yyStart. Closing comment brackets are recognized only
  674. if the scanner is in start state comment.  Upon their recognition the  nesting
  675. level  is  decreased.  Should the nesting level reach zero the comment is fin-
  676. ished and we change the state back to  STD  using  yyStart  again.  While  the
  677. scanner  is  in start state comment everything except opening and closing com-
  678. ment brackets is skipped by specifying an empty action. The last rule specify-
  679. ing  the  structure  of  decimal numbers is recognized only in the start state
  680. STD.
  681.  
  682.      The problem of how to declare the variable for counting the nesting level
  683. of comments is solved in section 3.7.
  684.  
  685. 3.6.  Scanner Name
  686.  
  687.      A specification may be optionally headed by a name for the scanner to  be
  688. generated:
  689.  
  690.     Example:
  691.     SCANNER lexer
  692.  
  693. The identifier is used to derive the names of the scanner and source  modules,
  694. the file name for the scanner tables, and a prefix for the objects exported by
  695. the scanner.  If the name is missing it defaults to Scanner.  In the following
  696. we  refer to this name by <Scanner>. The prefixes <Scanner> and <Scanner>_ are
  697. generated only if this clause is present. Otherwise they are omitted in  order
  698. to be compatible with former versions of Rex.
  699.  
  700. 3.7.  Target Code
  701.  
  702.      The actions associated with regular expressions may need variables or  in
  703. general arbitrary declarations to perform their task.  A scanner specification
  704. may be preceded by several kinds of sections written in the  target  language.
  705. The syntax rules for actions apply to these sections, too.  These sections are
  706. copied unchanged and unchecked to  the  generated  scanner  at  the  following
  707. places:
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.                                      Rex                                    10
  719.  
  720.  
  721. -    Target code after the keyword EXPORT is  included  in  the  specification
  722.      part  (definition  module)  of the generated scanner. It allows to extend
  723.      the set of objects exported by the scanner module.  If not  given  it  is
  724.      predefined as described below.
  725.  
  726. -    Target code after the keyword GLOBAL is included in the scanner module at
  727.      level 0, that is the extent of variables given in this section is the run
  728.      time of the whole program.  If not given it is  predefined  as  described
  729.      below.
  730.  
  731. -    Target code after the keyword LOCAL is included in  the  scanner  routine
  732.      called  <Scanner>_GetToken  (at level 1), that is the extent of variables
  733.      given in this section is one invocation of this routine.
  734.  
  735. -    Target  code  after  the  keyword  BEGIN  is  included  in  the   routine
  736.      <Scanner>_BeginScanner  which may be called to initialize the data struc-
  737.      tures declared in the sections EXPORT and GLOBAL.
  738.  
  739. -    Target  code  after  the  keyword  CLOSE  is  included  in  the   routine
  740.      <Scanner>_CloseScanner  which  may  be called after scanning is finished.
  741.      This statements can be used to finalize the data structures  declared  in
  742.      the sections EXPORT and GLOBAL.
  743.  
  744. -    Target code after the keyword DEFAULT is included in the scanner  routine
  745.      to  be executed whenever a character is not matched by one of the regular
  746.      expressions. It can be used to detect illegal characters for example.  If
  747.      not given it is predefined as described below.
  748.  
  749. -    Target code after the keyword EOF is included in the scanner  routine  to
  750.      be  executed upon reaching the end of the input. It can be used to return
  751.      a value different from the predefined one (<Scanner>_EofToken = 0) or  to
  752.      check for unclosed comments or strings for example.
  753.  
  754.      If the EXPORT, GLOBAL, and DEFAULT sections are not  used  the  following
  755. predefined declarations are included:
  756.  
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.                                      Rex                                    11
  784.  
  785.  
  786.     If the target language is C:
  787.     EXPORT {
  788.     # include "Positions.h"
  789.     typedef struct { tPosition Position; } <Scanner>_tScanAttribute;
  790.     extern void <Scanner>_ErrorAttribute (int Token,
  791.                                           <Scanner>_tScanAttribute * Attribute);
  792.     }
  793.     GLOBAL {
  794.     void <Scanner>_ErrorAttribute (Token, Attribute)
  795.        int Token;
  796.        <Scanner>_tScanAttribute * Attribute;
  797.        { }
  798.     }
  799.     DEFAULT {
  800.        yyEcho;
  801.     }
  802.  
  803.  
  804.     If the target language is Modula-2:
  805.     EXPORT {
  806.     IMPORT Positions;
  807.     TYPE tScanAttribute = RECORD Position: Positions.tPosition; END;
  808.     PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  809.     }
  810.     GLOBAL {
  811.     PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  812.        BEGIN
  813.        END ErrorAttribute;
  814.     }
  815.     DEFAULT {
  816.        yyEcho;
  817.     }
  818.  
  819.  
  820.      These two sections import the type tPosition from a  module  named  Posi-
  821. tions  and  they declare the type <Scanner>_tScanAttribute as well as the pro-
  822. cedure <Scanner>_ErrorAttribute. These items are needed  in  combination  with
  823. parser   generators.    A   variable   called   <Scanner>_Attribute   of  type
  824. <Scanner>_tScanAttribute is used to communicate additional properties  of  the
  825. tokens  from the scanner to the parser.  The type <Scanner>_tScanAttribute has
  826. to be a struct (record) type with at least one member (field) called  Position
  827. of  type  tPosition.  tPosition has to be a struct (record) type with at least
  828. two members (fields) called Line and Column (see  section  3.8.).  It  can  be
  829. imported  from the predefined module Positions or from a user modified version
  830. of it.
  831.  
  832.      During automatic error repair a parser may insert tokens.  In  this  case
  833. the  parser  calls the procedure <Scanner>_ErrorAttribute to ask for the addi-
  834. tional properties of an inserted token which is given by the parameter  Token.
  835. The types tPosition and <Scanner>_tScanAttribute are predefined as given above
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.                                      Rex                                    12
  847.  
  848.  
  849. and the procedure <Scanner>_ErrorAttribute is empty. If only one of  the  sec-
  850. tions EXPORT or GLOBAL is used, it has to contain declarations consistent with
  851. the remaining predefined ones.
  852.  
  853. 3.8.  Source Position
  854.  
  855.      The generated scanners automatically compute the line and column position
  856. of every token. This position can be accessed via the fields Position.Line and
  857. Position.Column of the global variable <Scanner>_Attribute as described in the
  858. section about the Scanner Interface.  The source position is computed automat-
  859. ically if the action of a rule is preceded by a colon like in all the examples
  860. so  far.  However, if the character '-' is appended to the colon, the calcula-
  861. tion of the source position can be disabled for a rule.
  862.  
  863.      There are mainly two reasons for not to compute the position. First, some
  864. "compound"  tokens  have  to be recognized by the combination of several rules
  865. (usually in connection with a start state). In order to get the correct  posi-
  866. tion,  which is the position yielded by the first rule, the calculation of the
  867. position has to be disabled for the following rules.
  868.  
  869.     Example (Pascal strings):
  870.     START string
  871.     RULE
  872.     #STD#    '              :  {yyStart (string);}
  873.     #string# - {'\t\n} +    :- {}
  874.     #string# ''             :- {}
  875.     #string# '              :- {yyStart (STD); return SymString;}
  876.  
  877.  
  878.      Second, there is no need to calculate the source position in  rules  that
  879. skip  input  characters  without returning a token. In this case disabling the
  880. computation of the position yields an increase in  run  time  efficiency.  The
  881. typical  examples  are  comments. The example given in the chapter about Start
  882. States should be rewritten as follows:
  883.  
  884.     Example (Modula-2 comments):
  885.     START comment
  886.     RULE
  887.                "(*"         :- {++ level; yyStart (comment);}
  888.     #comment#  "*)"         :- {-- level; if (level == 0) yyStart (STD);}
  889.     #comment#  "(" | "*" | - {*(\t\n} + :- {}
  890.  
  891.  
  892. 4.  Predefined Items
  893.  
  894.      Rex knows several predefined items described in the next sections.
  895.  
  896. 4.1.  Definitions
  897.  
  898.      The identifier ANY is predefined to match one arbitrary character  except
  899. newline.
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910.                                      Rex                                    13
  911.  
  912.  
  913.     DEFINE ANY = - { \n } .
  914.  
  915.  
  916. 4.2.  Start States
  917.  
  918.      The identifier STD is predefined to denote the standard  start  state  of
  919. Rex.  The generated scanners are initially in this state.
  920.  
  921.     START STD
  922.  
  923.  
  924. 4.3.  Rules
  925.  
  926.      The 4 for rules given below  are  predefined  after  the  user  specified
  927. rules.   By giving own rules the user can overwrite these because of the stra-
  928. tegy to solve ambiguities. The predefined rules help to calculate the line and
  929. column positions and to skip blanks efficiently.
  930.  
  931.     RULE
  932.     " "     :- {}
  933.     \t      :- {yyTab;}
  934.     \n      :- {yyEol (0);}
  935.     ANY     :- {yyEcho;}
  936.  
  937.  
  938. 4.4.  Action Statements
  939.  
  940.      The following statements can be used within the actions  associated  with
  941. regular expressions:
  942.  
  943. <Scanner>_GetWord (v);
  944.             This statement gives access to the matched character sequence.
  945.             In C the sequence is returned in the variable v which must  be  of
  946.             type  char  v  [  ].  Additionally  the  length of the sequence is
  947.             returned as result of the function.
  948.             In Modula-2 the sequence is returned in the variable v which  must
  949.             be of type Strings.tString.
  950.  
  951. <Scanner>_GetLower (v);
  952.             Like <Scanner>_GetWord, except that every letter is normalized  to
  953.             lower case.
  954.  
  955. <Scanner>_GetUpper (v);
  956.             Like <Scanner>_GetWord, except that every letter is normalized  to
  957.             upper case.
  958.  
  959. yyEcho;     The matched character sequence is printed on standard output.
  960.  
  961. yyLess (n); The matched character sequence is truncated to the first n charac-
  962.             ters.   The  other characters are rescanned for the next character
  963.             sequence.
  964.  
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.                                      Rex                                    14
  976.  
  977.  
  978. yyStart (s);
  979.             The start state is changed to state s.
  980.  
  981. yyPrevious; The start state is changed to the  state  valid  before  the  last
  982.             execution of yyStart or yyPrevious.
  983.  
  984. yyStartState
  985.             This is not a  statement  but  an  expression  of  type  short  or
  986.             SHORTCARD,  respectively,  whose value is the current start state.
  987.             It can be used to  execute  different  statements  in  one  action
  988.             depending on the current start state.
  989.  
  990. yyTab;      This statement should be used if a regular expression is specified
  991.             by  the  user  to process tab characters. Its purpose is to update
  992.             the internal variable to calculate the column position of  tokens.
  993.             yyTab  works only if the tab character exclusively is specified by
  994.             a rule.
  995.  
  996. yyTab1 (a); Like yyTab this statement should be used if a  regular  expression
  997.             is specified by the user to process tab characters. Its purpose is
  998.             to update the internal variable to calculate the  column  position
  999.             of  tokens. yyTab1 works if the tab character is embedded in other
  1000.             characters. The parameter a must specify the number of  characters
  1001.             before the tab character.
  1002.  
  1003. yyEol (n);  This statement should be used if a regular expression is specified
  1004.             by  the  user to process newline characters. Its purpose is to up-
  1005.             date the internal variables to calculate the line and column posi-
  1006.             tion  of  tokens.  yyEol should be executed once for every newline
  1007.             character matched.  The parameter n should specify the  number  of
  1008.             characters  matched  after  the  last newline character. In simple
  1009.             cases where the pattern consists only of a newline  character  one
  1010.             invocation of yyEol (0); is sufficient.
  1011.  
  1012. 5.  Interface of the Generated Scanners
  1013.  
  1014.      The scanners generated by Rex offer an interface to be  used  by  a  main
  1015. program like e. g. a parser and they require a source module for blocked input
  1016. of characters to obey a certain interface.  The structure of these two  inter-
  1017. faces is independent from a specific target language. As the syntactic details
  1018. vary from one target language to another we discuss the interfaces in the fol-
  1019. lowing target language specific chapters.
  1020.  
  1021. 5.1.  C
  1022.  
  1023.      It has been already mentioned that the prefixes <Scanner> and  <Scanner>_
  1024. are generated only if the keyword SCANNER is present. Otherwise they are omit-
  1025. ted in order to be compatible with former versions of Rex.
  1026.  
  1027. 5.1.1.  Scanner Interface
  1028.  
  1029.      The scanners generated by Rex offer an interface given by  the  following
  1030. specification file named <Scanner>.h:
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.                                      Rex                                    15
  1042.  
  1043.  
  1044.     # include "Positions.h"
  1045.     typedef struct { tPosition Position; } <Scanner>_tScanAttribute;
  1046.     extern  void <Scanner>_ErrorAttribute (int Token,
  1047.                                            <Scanner>_tScanAttribute * Attribute);
  1048.     # define                <Scanner>_EofToken        0
  1049.     extern  char *          <Scanner>_TokenPtr        ;
  1050.     extern  short           <Scanner>_TokenLength     ;
  1051.     extern  <Scanner>_tScanAttribute <Scanner>_Attribute;
  1052.     extern  void         (* <Scanner>_Exit) ()        ;
  1053.     extern  void            <Scanner>_BeginScanner    ();
  1054.     extern  void            <Scanner>_BeginFile       (char * FileName);
  1055.     extern  int             <Scanner>_GetToken        ();
  1056.     extern  int             <Scanner>_GetWord         (char * Word);
  1057.     extern  int             <Scanner>_GetLower        (char * Word);
  1058.     extern  int             <Scanner>_GetUpper        (char * Word);
  1059.     extern  void            <Scanner>_CloseFile       ();
  1060.     extern  void            <Scanner>_CloseScanner    ();
  1061.  
  1062.  
  1063. -    The procedure <Scanner>_GetToken is the central scanning routine. It  re-
  1064.      turns  the  next token found in the input or whatever is specified in the
  1065.      actions associated with the regular expressions.
  1066.  
  1067. -    The procedure <Scanner>_BeginFile may be called to open an input file  or
  1068.      a  nested  include  file.  It has one parameter of type 'char *' (string)
  1069.      which specifies the file name.  Include files up to a nesting depth of 15
  1070.      can be processed.  If not called input is read from standard input.
  1071.  
  1072. -    The procedure <Scanner>_CloseFile may be called to close the actual input
  1073.      file  (before  reaching  end  of file). <Scanner>_CloseFile is called au-
  1074.      tomatically by the scanner upon reaching end of file.
  1075.  
  1076. -    The procedure <Scanner>_BeginScanner may be  called  to  initialize  user
  1077.      data.
  1078.  
  1079. -    The procedure <Scanner>_CloseScanner may be called to finalize user data.
  1080.  
  1081. -    The     procedures     <Scanner>_GetWord,     <Scanner>_GetLower,     and
  1082.      <Scanner>_GetUpper  allow  access  to  the  matched character sequence as
  1083.      described in section 4.4.
  1084.  
  1085. -    Alternatively, the matched character sequence can be accessed  using  the
  1086.      variables       <Scanner>_TokenPtr       and       <Scanner>_TokenLength.
  1087.      <Scanner>_TokenPtr points to the beginning of the matched  character  se-
  1088.      quence. <Scanner>_TokenLength specifies the number of the matched charac-
  1089.      ters. Note, the matched character sequence is not terminated  by  a  '\0'
  1090.      character.
  1091.  
  1092. -    The variable <Scanner>_Attribute is supposed  to  communicate  additional
  1093.      properties  of  the last token. The value must be provided by appropriate
  1094.      action statements.  This variable  is  of  type  <Scanner>_tScanAttribute
  1095.  
  1096.  
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104.  
  1105.                                      Rex                                    16
  1106.  
  1107.  
  1108.      which has to be a struct type with at least one member called Position of
  1109.      type tPosition. tPosition has to be a  struct  type  with  at  least  two
  1110.      members called Line and Column. The values of Line and Column are comput-
  1111.      ed by the scanner, automatically. They indicate the  source  position  of
  1112.      the  actual  token.  The position of a token is the position of the first
  1113.      character of the token.  For  exceptions  see  section  3.8.   The  types
  1114.      <Scanner>_tScanAttribute  and  tPosition  are  predefined as given above.
  1115.      The definitions of these types can be changed  as  described  in  section
  1116.      3.7.
  1117.  
  1118. -    During automatic error repair a parser may insert tokens.  In  this  case
  1119.      the  parser  calls  the procedure <Scanner>_ErrorAttribute to ask for the
  1120.      additional properties of an inserted token which is given by the  parame-
  1121.      ter  Token.   The  procedure  should return in the second argument called
  1122.      <Scanner>_Attribute a default value for the additional properties of  the
  1123.      token Token.
  1124.  
  1125. -    The variable <Scanner>_Exit refers to a procedure which is called upon an
  1126.      internal  error in the scanner. The default procedure terminates the pro-
  1127.      gram execution. The variable  can  be  changed  to  achieve  a  different
  1128.      behaviour.
  1129.  
  1130. -    If the scanner reaches the end of the input it returns the special  token
  1131.      called <Scanner>_EofToken which is encoded by 0.
  1132.  
  1133. 5.1.2.  Source Interface
  1134.  
  1135.      The scanners generated by Rex need a source module for blocked  input  of
  1136. characters.  Rex  can provide a prototype source module which reads from stan-
  1137. dard input or any file. It is contained in  the  files  <Scanner>Source.h  and
  1138. <Scanner>Source.c.  The specification file <Scanner>Source.h consists of some-
  1139. thing like:
  1140.  
  1141.     extern int  <Scanner>_BeginSource  (char * FileName);
  1142.     extern int  <Scanner>_GetLine      (int File, char * Buffer, int Size);
  1143.     extern void <Scanner>_CloseSource  (int File);
  1144.  
  1145.  
  1146. -    <Scanner>_BeginSource is called from the scanner in order to  open  files
  1147.      or  to  initialize any other source of input. If not called input is read
  1148.      from standard input.
  1149.  
  1150. -    <Scanner>_GetLine is called to fill a buffer starting at address 'Buffer'
  1151.      with  a  block of maximal 'Size' characters. Lines are terminated by new-
  1152.      line characters (ASCII = 0xa). <Scanner>_GetLine returns  the  number  of
  1153.      characters  transferred.  Reasonable block sizes are between 128 and 2048
  1154.      or the length of a line. Smaller block sizes - especially block size 1  -
  1155.      will drastically slow down the scanner.
  1156.  
  1157. -    <Scanner>_CloseSource is called from the scanner at end of  file  respec-
  1158.      tively at end of input. It can be used to close files.
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.                                      Rex                                    17
  1171.  
  1172.  
  1173.      The body in the file <Scanner>Source.c has the following contents:
  1174.  
  1175.     # include "<Scanner>Source.h"
  1176.     # include "System.h"
  1177.     int <Scanner>_BeginSource (FileName)
  1178.        char * FileName;
  1179.     {  return OpenInput (FileName); }
  1180.     int <Scanner>_GetLine (File, Buffer, Size)
  1181.        int File; char * Buffer; int Size;
  1182.     {
  1183.        register int n = Read (File, Buffer, Size);
  1184.     # ifdef Dialog
  1185.     # define IgnoreChar ' '
  1186.     /* Add dummy after newline character in order to supply a lookahead for rex. */
  1187.     /* This way newline tokens are recognized without typing an extra line.      */
  1188.        if (n > 0 && Buffer [n - 1] == '0) Buffer [n ++] = IgnoreChar;
  1189.     # endif
  1190.        return n;
  1191.     }
  1192.     void <Scanner>_CloseSource (File)
  1193.        int File;
  1194.     {  Close (File); }
  1195.  
  1196.  
  1197.      The newline character may constitute a token of its own  in  applications
  1198. such  as  dialog  programs.  Like  for every other token, Rex needs at least a
  1199. look-ahead of one character to recognize this token. Therefore the user has to
  1200. type not only one extra character but a complete extra input line because usu-
  1201. ally input is line buffered by the operating system.  This  behaviour  is  un-
  1202. desirable.  The  problem can be solved by compiling the file <Scanner>Source.c
  1203. with the option -DDialog. This variant adds a dummy character after  the  new-
  1204. line  character to serve as lookahead. The dummy character should be a charac-
  1205. ter that is ignored such as e. g. a blank.
  1206.  
  1207. 5.1.3.  Scanner Driver
  1208.  
  1209.      To test a generated scanner a main program is necessary. Rex can  provide
  1210. a  minimal  main  program  in  the file <Scanner>Drv.c which can serve as test
  1211. driver.  It counts the tokens and looks like the following:
  1212.  
  1213.  
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.                                      Rex                                    18
  1235.  
  1236.  
  1237.     # include "Positions.h"
  1238.     # include "<Scanner>.h"
  1239.     main ()
  1240.     {
  1241.        int Token, Count = 0;
  1242.        char Word [256];
  1243.        <Scanner>_BeginScanner ();
  1244.        do {
  1245.           Token = <Scanner>_GetToken ();
  1246.           Count ++;
  1247.     # ifdef Debug
  1248.           if (Token != <Scanner>_EofToken) (void) <Scanner>_GetWord (Word);
  1249.           else Word [0] = '\0';
  1250.           WritePosition (stdout, <Scanner>_Attribute.Position);
  1251.           (void) printf ("%5d %s\n", Token, Word);
  1252.     # endif
  1253.        } while (Token != <Scanner>_EofToken);
  1254.        <Scanner>_CloseScanner ();
  1255.        (void) printf ("%d\n", Count);
  1256.        return 0;
  1257.     }
  1258.  
  1259.  
  1260. 5.2.  Modula-2
  1261.  
  1262. 5.2.1.  Scanner Interface
  1263.  
  1264.      The scanners generated by Rex offer an interface given by  the  following
  1265. definition module named <Scanner>.md:
  1266.  
  1267.     DEFINITION MODULE <Scanner>;
  1268.     IMPORT Positions, Strings;
  1269.     TYPE tScanAttribute = RECORD Position: Positions.tPosition; END;
  1270.     PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  1271.     CONST EofToken  = 0;
  1272.     VAR TokenLength : INTEGER;
  1273.     VAR Attribute   : tScanAttribute;
  1274.     VAR ScanTabName : ARRAY [0 .. 127] OF CHAR;
  1275.     VAR Exit        : PROC;
  1276.     PROCEDURE BeginScanner  ;
  1277.     PROCEDURE BeginFile     (FileName: ARRAY OF CHAR);
  1278.     PROCEDURE GetToken      (): INTEGER;
  1279.     PROCEDURE GetWord       (VAR Word: Strings.tString);
  1280.     PROCEDURE GetLower      (VAR Word: Strings.tString);
  1281.     PROCEDURE GetUpper      (VAR Word: Strings.tString);
  1282.     PROCEDURE CloseFile     ;
  1283.     PROCEDURE CloseScanner  ;
  1284.     END <Scanner>.
  1285.  
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.                                      Rex                                    19
  1296.  
  1297.  
  1298. -    The procedure GetToken is the central scanning routine.  It  returns  the
  1299.      next token found in the input or whatever is specified in the actions as-
  1300.      sociated with the regular expressions.
  1301.  
  1302. -    The array ScanTabName specifies the  name  of  the  file  containing  the
  1303.      scanner tables.  It is initialized with the string "Scan.Tab". Therefore,
  1304.      the scanner tables are read by default from a file with this name in  the
  1305.      current  directory.   If a different name or location is desired an arbi-
  1306.      trary path name can be assigned to this array before calling GetToken the
  1307.      first time.
  1308.  
  1309. -    The procedure BeginFile may be called to open an input file or  a  nested
  1310.      include  file.  The  parameter FileName specifies the file name.  Include
  1311.      files up to a nesting depth of 15 can be processed.  If not called  input
  1312.      is read from standard input.
  1313.  
  1314. -    The procedure CloseFile may be called to close the actual input file (be-
  1315.      fore  reaching  end  of  file).  CloseFile is called automatically by the
  1316.      scanner upon reaching end of file.
  1317.  
  1318. -    The procedure BeginScanner may be called to initialize user data.
  1319.  
  1320. -    The procedure CloseScanner may be called to finalize user data.
  1321.  
  1322. -    The procedures GetWord,  GetLower,  and  GetUpper  allow  access  to  the
  1323.      matched character sequence as described in section 4.4.
  1324.  
  1325. -    The variable TokenLength specifies the number of the matched characters.
  1326.  
  1327. -    The variable Attribute is supposed to communicate  additional  properties
  1328.      of  the  last  token.  The  value  must be provided by appropriate action
  1329.      statements.  This variable is of type tScanAttribute which has  to  be  a
  1330.      record  type  with  at least one field called Position of type tPosition.
  1331.      tPosition has to be a record type with at least two  fields  called  Line
  1332.      and  Column.  The  values of Line and Column are computed by the scanner,
  1333.      automatically. They indicate the source position of the actual token. The
  1334.      position  of a token is the position of the first character of the token.
  1335.      For exceptions see section 3.8.  The types tScanAttribute  and  tPosition
  1336.      are  predefined  as  given  above.  The definitions of these types can be
  1337.      changed as described in section 3.7.
  1338.  
  1339. -    During automatic error repair a parser may insert tokens.  In  this  case
  1340.      the  parser  calls the procedure ErrorAttribute to ask for the additional
  1341.      properties of an inserted token which is given by  the  parameter  Token.
  1342.      The procedure should return in the second argument called Attribute a de-
  1343.      fault value for the additional properties of the token Token.
  1344.  
  1345. -    The variable Exit refers to a procedure which is called upon an  internal
  1346.      error in the scanner. The default procedure terminates the program execu-
  1347.      tion. The variable can be changed to achieve a different behaviour.
  1348.  
  1349. -    If the scanner reaches the end of the input it returns the special  token
  1350.      called EofToken which is encoded by 0.
  1351.  
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.                                      Rex                                    20
  1362.  
  1363.  
  1364. 5.2.2.  Source Interface
  1365.  
  1366.      The scanners generated by Rex need a source module for blocked  input  of
  1367. characters.  Rex  can provide a prototype source module which reads from stan-
  1368. dard  input.  It  is   contained   in   the   files   <Scanner>Source.md   and
  1369. <Scanner>Source.mi.   The definition module in the file <Scanner>Source.md has
  1370. the following contents:
  1371.  
  1372.     DEFINITION MODULE <Scanner>Source;
  1373.     FROM SYSTEM     IMPORT ADDRESS;
  1374.     FROM System     IMPORT tFile;
  1375.     PROCEDURE BeginSource (FileName: ARRAY OF CHAR): tFile;
  1376.     PROCEDURE GetLine (File: tFile; Buffer: ADDRESS; Size: CARDINAL): INTEGER;
  1377.     PROCEDURE CloseSource (File: tFile);
  1378.     END <Scanner>Source.
  1379.  
  1380.  
  1381. -    BeginSource is called from the scanner in order to open files or to  ini-
  1382.      tialize  any  other  source  of  input.  If not called input is read from
  1383.      standard input.
  1384.  
  1385. -    GetLine is called to fill a buffer starting at address  'Buffer'  with  a
  1386.      block of maximal 'Size' characters. Lines are terminated by newline char-
  1387.      acters  (ASCII  =  12C).  GetLine  returns  the  number   of   characters
  1388.      transferred.  Reasonable  block  sizes  are  between  128 and 2048 or the
  1389.      length of a line. Smaller block sizes - especially block size  1  -  will
  1390.      drastically slow down the scanner.
  1391.  
  1392. -    CloseSource is called from the scanner at end of file respectively at end
  1393.      of input. It can be used to close files.
  1394.  
  1395.  
  1396.      The implementation module in the file <Scanner>Source.mi has the  follow-
  1397. ing contents:
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.  
  1406.  
  1407.  
  1408.  
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414.  
  1415.  
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422.  
  1423.  
  1424.  
  1425.                                      Rex                                    21
  1426.  
  1427.  
  1428.     IMPLEMENTATION MODULE <Scanner>Source;
  1429.     FROM SYSTEM     IMPORT ADDRESS;
  1430.     FROM System     IMPORT tFile, OpenInput, Read, Close;
  1431.     PROCEDURE BeginSource (FileName: ARRAY OF CHAR): tFile;
  1432.        BEGIN
  1433.           RETURN OpenInput (FileName);
  1434.        END BeginSource;
  1435.     PROCEDURE GetLine (File: tFile; Buffer: ADDRESS; Size: CARDINAL): INTEGER;
  1436.        CONST IgnoreChar = ' ';
  1437.        VAR n        : INTEGER;
  1438.        VAR BufferPtr: POINTER TO ARRAY [0..30000] OF CHAR;
  1439.        BEGIN
  1440.        (* # ifdef Dialog
  1441.           n := Read (File, Buffer, Size);
  1442.     (* Add dummy after newline character in order to supply a lookahead for rex. *)
  1443.     (* This way newline tokens are recognized without typing an extra line.      *)
  1444.           BufferPtr := Buffer;
  1445.           IF (n > 0) AND (BufferPtr^[n - 1] = 012C) THEN
  1446.              BufferPtr^[n] := IgnoreChar; INC (n); END;
  1447.           RETURN n;
  1448.           # else *)
  1449.           RETURN Read (File, Buffer, Size);
  1450.        (* # endif *)
  1451.        END GetLine;
  1452.     PROCEDURE CloseSource (File: tFile);
  1453.        BEGIN
  1454.           Close (File);
  1455.        END CloseSource;
  1456.     END <Scanner>Source.
  1457.  
  1458.  
  1459.      The newline character may constitute a token of its own  in  applications
  1460. such  as  dialog  programs.  Like  for every other token, Rex needs at least a
  1461. look-ahead of one character to recognize this token. Therefore the user has to
  1462. type not only one extra character but a complete extra input line because usu-
  1463. ally input is line buffered by the operating system.  This  behaviour  is  un-
  1464. desirable. The problem can be solved by modifying the procedure GetLine in the
  1465. file <Scanner>Source.mi. The variant in the comment (* # ifdef  Dialog  ...  #
  1466. else  *) adds a dummy character after the newline character to serve as looka-
  1467. head. The dummy character should be a character that is ignored such as e.  g.
  1468. a blank.
  1469.  
  1470. 5.2.3.  Scanner Driver
  1471.  
  1472.      To test a generated scanner a main program is necessary. Rex can  provide
  1473. a  minimal  main  program  in the file <Scanner>Drv.mi which can serve as test
  1474. driver.  It counts the tokens and looks like the following:
  1475.  
  1476.     MODULE <Scanner>Drv;
  1477.     FROM <Scanner>  IMPORT BeginScanner, GetToken, GetWord, Attribute, EofToken,
  1478.  
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488.                                      Rex                                    22
  1489.  
  1490.  
  1491.                            CloseScanner;
  1492.     FROM Strings    IMPORT tString, WriteL;
  1493.     FROM IO         IMPORT StdOutput, WriteI, WriteC, WriteNl, CloseIO;
  1494.     FROM Positions  IMPORT WritePosition;
  1495.     FROM System     IMPORT Exit;
  1496.     VAR Token       : INTEGER;
  1497.         Word        : tString;
  1498.         Debug       : BOOLEAN;
  1499.         Count       : INTEGER;
  1500.     BEGIN
  1501.        Debug := FALSE;
  1502.        Count := 0;
  1503.        BeginScanner;
  1504.        REPEAT
  1505.           Token := GetToken ();
  1506.           INC (Count);
  1507.           IF Debug THEN
  1508.              GetWord (Word);
  1509.              WritePosition (StdOutput, Attribute.Position);
  1510.              WriteI (StdOutput, Token, 5);
  1511.              WriteC (StdOutput, ' ');
  1512.              WriteL (StdOutput, Word);
  1513.           END;
  1514.        UNTIL Token = EofToken;
  1515.        CloseScanner;
  1516.        WriteI (StdOutput, Count, 0);
  1517.        WriteNl (StdOutput);
  1518.        CloseIO;
  1519.        Exit (0);
  1520.     END <Scanner>Drv.
  1521.  
  1522.  
  1523. 6.  Usage
  1524. NAME
  1525.    rex - generator of lexical analysers
  1526. SYNOPSIS
  1527.    rex [ -options ] [ -ldir ] [ file ]
  1528. DESCRIPTION
  1529.    Rex generates programs to be used in lexical analysis of  text.  A  typical
  1530.    application  is  the  generation  of scanners for compilers. The input file
  1531.    contains regular expressions to be searched for, and actions written  in  C
  1532.    or  Modula-2  to  be executed when strings according to the expressions are
  1533.    found.  Unrecognized portions of the input are copied to  standard  output.
  1534.    To  be  able  to  recognize tokens depending on their context, Rex provides
  1535.    start states to handle left context and the right context can be  specified
  1536.    by  an additional regular expression.  If several regular expressions match
  1537.    the input characters, the longest match is preferred. If  there  are  still
  1538.    several possibilities, the regular expression given first in the specifica-
  1539.    tion is chosen.
  1540.  
  1541.  
  1542.  
  1543.  
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.                                      Rex                                    23
  1551.  
  1552.  
  1553.    Rex generated scanners automatically provide the line and  column  position
  1554.    of  each token. For languages like Pascal and Ada where the case of letters
  1555.    is insignificant tokens can be normalized to lower or upper case. There are
  1556.    predefined  rules  to  skip  white space like blanks, tabs, or newlines and
  1557.    there is a mechanism to handle include files.  The generated  scanners  are
  1558.    table-driven deterministic finite automatons.
  1559. OPTIONS
  1560.  
  1561. a    generate all (= sdm)
  1562.  
  1563. m    generate a lexical analyser in Modula-2 (default)
  1564.  
  1565. c    generate a lexical analyser in C
  1566.  
  1567. d    generate a definition module for the lexical analyser
  1568.  
  1569. s    generate support modules:
  1570.      - a source module for input
  1571.      - a main program to be used as test driver
  1572.  
  1573. r    reduce the number of generated case/switch labels. Might be necessary due
  1574.      to  compiler restrictions. Effects: slower scanner (2-4%), larger tables,
  1575.      same scanner size.
  1576.  
  1577. i    use ISO 8 bit code (default: ASCII 7 bit code)
  1578.  
  1579. o    optimize table size
  1580.      Effects: slower scanner (0-15%), small tables, long generation time (fac-
  1581.      tor 1-10)
  1582.  
  1583. n    do not optimize table size
  1584.      Effects: fast scanner, large tables (factor 1-10), short generation time
  1585.  
  1586.      default: improve table size
  1587.      Effects: slower scanner (0-5%), medium size tables (factor  1-2),  medium
  1588.      generation time (factor 1-2)
  1589.  
  1590. w    suppress warnings
  1591.  
  1592. g    generate # line directives
  1593.  
  1594. b    do not partition charcater set into blocks
  1595.  
  1596. 1    print statistics about the generated lexical analyser
  1597.  
  1598. ldir dir is the directory where Rex finds its table and data files
  1599.   FILES
  1600.      if output is in C:
  1601.      <Scanner>.h         specification of the generated scanner
  1602.      <Scanner>.c         body of the generated scanner
  1603.  
  1604.  
  1605.  
  1606.  
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.                                      Rex                                    24
  1614.  
  1615.  
  1616.      <Scanner>Source.h   specification of support module source
  1617.      <Scanner>Source.c   body of support module source
  1618.      <Scanner>Drv.c      main program to serve as test driver
  1619.      if output is in Modula-2:
  1620.      <Scanner>.md        definition module of the generated scanner
  1621.      <Scanner>.mi        implementation module of the generated scanner
  1622.      <Scanner>Source.md  definition module of support module source
  1623.      <Scanner>Source.mi  implementation module of support module source
  1624.      <Scanner>Drv.mi     main program to serve as test driver
  1625.      <Scanner>.Tab       tables to control the generated scanner
  1626.   SEE ALSO
  1627.      J. Grosch: "Rex - A  Scanner  Generator",  GMD  Forschungsstelle  an  der
  1628.      Universitaet Karlsruhe, Compiler Generation Report No. 5, 1987
  1629.      J. Grosch: "Efficient Generation of Lexical Analysers", Software -  Prac-
  1630.      tice & Experience, 19 (11), 1089-1103, Nov. 1989
  1631.  
  1632. 7.  Implementation
  1633.  
  1634.      Rex is implemented by a 5,000 line Modula-2 program.  The  program  makes
  1635. heavy use of a library of reusable Modula-2 modules currently comprising 3,000
  1636. lines of code [Gro87].  Of the 5,000 lines of Rex 1,500 lines are generated by
  1637. tools:
  1638.  
  1639. -    500 lines for the scanner are generated by Rex itself.
  1640.  
  1641. -    1000 lines for the parser are generated by the LALR(1)  parser  generator
  1642.      lalr.
  1643.  
  1644.      How can Rex generate a part of itself before  its  existence?  Well,  the
  1645. scanner  has been bootstrapped using LEX. The first version of the scanner was
  1646. a separate C program generated by LEX which wrote the internal  representation
  1647. of  the  tokens on a file.  A simple hand written scanner read the tokens from
  1648. this file during construction of Rex. After Rex was operational it could  gen-
  1649. erate its own scanner in  Modula-2.
  1650.  
  1651.      And how is Rex working? It differentiates between  constant  regular  ex-
  1652. pressions and non-constant ones as defined in [Gro89].  The non-constant regu-
  1653. lar expressions constitute a nondeterministic finite automaton.  The so-called
  1654. subset construction algorithm is used for conversion into a deterministic fin-
  1655. ite automaton.  Then an algorithm to minimize the number of states is applied.
  1656. After  extending  the automaton to a tunnel automaton the constant regular ex-
  1657. pressions are added in linear time using the algorithm described  in  [Gro89].
  1658. The sparse matrix to control the automaton is compressed into a data structure
  1659. called "comb vector" [ASU86] to save space.
  1660.  
  1661.      The key to the performance of scanners generated by Rex lies in the  fol-
  1662. lowing facts:
  1663.  
  1664. -    access to the "comb vector" table is fast
  1665.  
  1666.  
  1667.  
  1668.  
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674.  
  1675.  
  1676.                                      Rex                                    25
  1677.  
  1678.  
  1679. -    input happens rarely because blocks of characters are transferred
  1680.  
  1681. -    no check for the last character of a block is necessary  because  of  the
  1682.      sentinel technique used
  1683.  
  1684. -    the same holds for the check of stack underflow for the stack  to  record
  1685.      the passed states
  1686.  
  1687. -    the treatment of right context is efficient and only necessary in  a  few
  1688.      cases because partial evaluation has been applied
  1689.  
  1690. 8.  Differences to LEX
  1691.  
  1692. Some specialists might want to know about the differences between Rex and  LEX
  1693. [Les75] (see Table):
  1694.  
  1695. Advantages of Rex:
  1696.  
  1697. +    The standard or initial start state has a documented name: STD.
  1698.  
  1699. +    The list of start states can be inverted using the operator NOT to speci-
  1700.      fy that a rule is valid in all states except the listed ones.
  1701.  
  1702. +    The specifications can be written unformatted - white space in  the  form
  1703.      of blanks, tabs, and newlines is skipped.
  1704.  
  1705. +    Identifiers used to  refer  to  named  regular  expressions  are  written
  1706.      without enclosing braces '{' '}'.
  1707.  
  1708.              Table: Syntactical differences between Rex and LEX:
  1709.  
  1710. Meaning                                LEX             Rex
  1711. ______________________________________________________________________________________
  1712. delimiter for character classes        [ ]             { }
  1713. complement of character classes        [^ ]            - { }
  1714. any character                          .               ANY
  1715. left justification                     ^               <
  1716. right justification                    $               >
  1717. replicator                             {n}             [n]
  1718. replicator                             {m,n}           [m-n]
  1719. delimiter for start states             < >             # #
  1720. escape representation for characters   \octal       \decimal
  1721. scanner routine                        yylex           <Scanner>_GetToken
  1722. access to matched string               yytext          <Scanner>_GetWord ( )
  1723. length of matched string               yyleng          result of <Scanner>_GetWord ( )
  1724. output of matched string               ECHO            yyEcho
  1725. retain part of matched string          yyless          yyLess
  1726. initial start state                    INITIAL         STD
  1727. change of start state                  BEGIN           yyStart ( )
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.                                      Rex                                    26
  1742.  
  1743.  
  1744. +    Rex automatically calculates the source position of  the  tokens  in  the
  1745.      fields Line and Column of the variable <Scanner>_Attribute.
  1746.  
  1747. +    There are predefined rules to skip the white space characters.
  1748.  
  1749. +    Include files up to a nesting depth of 15 can be processed.
  1750.  
  1751. +    Routines are provided to normalize tokens to upper or lower case  charac-
  1752.      ters.
  1753.  
  1754. +    No adjustment of the internal data structures are necessary to be able to
  1755.      process large specifications.
  1756.  
  1757. Disadvantages of Rex:
  1758.  
  1759. -    The action statement yymore is not available.
  1760.  
  1761. -    The action statement REJECT is not available -  Rex  can  only  find  one
  1762.      solution and not all like LEX.
  1763.  
  1764. -    The redirection of input with the procedure yywrap is not available.
  1765.  
  1766. -    The character set is fixed to the one of the host computer. There  is  no
  1767.      way  to specify a different character set to be able to generate scanners
  1768.      for target computers with a different character set.
  1769.  
  1770.  
  1771.  
  1772.  
  1773.  
  1774.  
  1775.  
  1776.  
  1777.  
  1778.  
  1779.  
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.  
  1787.  
  1788.  
  1789.  
  1790.  
  1791.  
  1792.  
  1793.  
  1794.  
  1795.  
  1796.  
  1797.  
  1798.  
  1799.  
  1800.  
  1801.  
  1802.  
  1803.  
  1804.  
  1805.  
  1806.                                      Rex                                    27
  1807.  
  1808.  
  1809. Appendix 1: Syntax of the Specification Language
  1810.  
  1811.  
  1812. specification   : [name] [code] [define] [start] rules
  1813.                 .
  1814. name            : SCANNER [Ident]
  1815.                 .
  1816. code            :
  1817.                 | code EXPORT  TargetCode
  1818.                 | code GLOBAL  TargetCode
  1819.                 | code LOCAL   TargetCode
  1820.                 | code BEGIN   TargetCode
  1821.                 | code CLOSE   TargetCode
  1822.                 | code DEFAULT TargetCode
  1823.                 | code EOF     TargetCode
  1824.                 .
  1825. define          : DEFINE definition *
  1826.                 .
  1827. start           : START identList
  1828.                 .
  1829. rules           : RULE  rule *
  1830.                 | RULES rule *
  1831.                 .
  1832. definition      : Ident '=' regExpr '.'
  1833.                 .
  1834. identList       : Ident
  1835.                 | identList Ident
  1836.                 | identList ',' Ident
  1837.                 .
  1838. rule            : patternList ':'  TargetCode
  1839.                 | patternList ':-' TargetCode
  1840.                 .
  1841. patternList     : pattern
  1842.                 | patternList ',' pattern
  1843.                 .
  1844. pattern         : [startStates] ['<'] regExpr ['/' regExpr] ['>']
  1845.                 .
  1846. startStates     : '#' identList '#'
  1847.                 | NOT '#' identList '#'
  1848.                 .
  1849. regExpr         : regExpr '|' regExpr
  1850.                 | regExpr regExpr
  1851.                 | regExpr '+'
  1852.                 | regExpr '*'
  1853.                 | regExpr '?'
  1854.                 | regExpr '[' Number ']'
  1855.                 | regExpr '[' Number '-' Number ']'
  1856.                 | '(' regExpr ')'
  1857.                 | charSet
  1858.                 | Char
  1859.                 | Ident
  1860.                 | String
  1861.                 | Number
  1862.  
  1863.  
  1864.  
  1865.  
  1866.  
  1867.  
  1868.  
  1869.  
  1870.  
  1871.  
  1872.                                      Rex                                    28
  1873.  
  1874.  
  1875.                 .
  1876. charSet         : '-' charSet
  1877.                 | '{' range * '}'
  1878.                 .
  1879. range           : Char
  1880.                 | Char '-' Char
  1881.                 .
  1882. Char            : character
  1883.                 | '\' digit +
  1884.                 | '\' n
  1885.                 | '\' t
  1886.                 | '\' v
  1887.                 | '\' b
  1888.                 | '\' r
  1889.                 | '\' f
  1890.                 | '\' character
  1891.                 .
  1892. Ident           : letter letter_or_digit *
  1893.                 .
  1894. letter_or_digit : letter
  1895.                 | digit
  1896.                 | '_'
  1897.                 .
  1898. String          : '"' character * '"'
  1899.                 .
  1900. Number          : digit +
  1901.                 .
  1902. Target_code     : '{' character * '}'
  1903.                 .
  1904.  
  1905.  
  1906.  
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918.  
  1919.  
  1920.  
  1921.  
  1922.  
  1923.  
  1924.  
  1925.  
  1926.  
  1927.  
  1928.  
  1929.  
  1930.  
  1931.  
  1932.  
  1933.  
  1934.  
  1935.  
  1936.  
  1937.                                      Rex                                    29
  1938.  
  1939.  
  1940. Appendix 2: Example Specification of a Modula-2-Scanner in C
  1941.  
  1942.  
  1943. GLOBAL  {
  1944. # include "Memory.h"
  1945. # include "StringMem.h"
  1946. # include "Idents.h"
  1947. int level = 0;
  1948. void ErrorAttribute (Token, Attribute)
  1949.    int Token;
  1950.    tScanAttribute Attribute;
  1951.    {
  1952.    }
  1953. }
  1954. LOCAL   {
  1955.    char         Word [256];
  1956.    tIdent       ident   ;
  1957.    tStringRef   ref     ;
  1958.    int          length  ;
  1959. }
  1960. DEFAULT {
  1961.    printf ("illegal character: "); yyEcho; printf ("\n");
  1962. }
  1963. DEFINE
  1964.    digit        = {0-9}         .
  1965.    letter       = {a-z A-Z}     .
  1966.    cmt          = - {*(\t\n}    .
  1967. START   comment
  1968. RULE
  1969.            "(*"         :- {++ level; yyStart (comment);}
  1970. #comment#  "*)"         :- {-- level; if (level == 0) yyStart (STD);}
  1971. #comment#  "(" | "*" | cmt + :- {}
  1972.    /* The procedure PutString is imported from the module StringMem(ory).
  1973.       It is used to store the string representation of some tokens.       */
  1974. #STD# digit +           ,
  1975. #STD# digit + / ".."    : {length = GetWord (Word);
  1976.                            ref = PutString (Word, length);
  1977.                            return 1;}
  1978. #STD# {0-7} + B         : {length = GetWord (Word);
  1979.                            ref = PutString (Word, length);
  1980.                            return 2;}
  1981. #STD# {0-7} + C         : {length = GetWord (Word);
  1982.                            ref = PutString (Word, length);
  1983.                            return 3;}
  1984. #STD# digit {0-9 A-F} * H : {
  1985.                            length = GetWord (Word);
  1986.                            ref = PutString (Word, length);
  1987.                            return 4;}
  1988.  
  1989.  
  1990.  
  1991.  
  1992.  
  1993.  
  1994.  
  1995.  
  1996.  
  1997.  
  1998.                                      Rex                                    30
  1999.  
  2000.  
  2001. #STD# digit + "." digit * (E {+\-} ? digit +) ? : {
  2002.                            length = GetWord (Word);
  2003.                            ref = PutString (Word, length);
  2004.                            return 5;}
  2005. #STD# ' - {\n'} * '     |
  2006.       \" - {\n"} * \"   : {length = GetWord (Word);
  2007.                            ref = PutString (Word, length);
  2008.                            return 6;}
  2009. #STD# "#"               : {return 7;}
  2010. #STD# "&"               : {return 8;}
  2011. #STD# "("               : {return 9;}
  2012. #STD# ")"               : {return 10;}
  2013. #STD# "*"               : {return 11;}
  2014. #STD# "+"               : {return 12;}
  2015. #STD# ","               : {return 13;}
  2016. #STD# "-"               : {return 14;}
  2017. #STD# "."               : {return 15;}
  2018. #STD# ".."              : {return 16;}
  2019. #STD# "/"               : {return 17;}
  2020. #STD# ":"               : {return 18;}
  2021. #STD# ":="              : {return 19;}
  2022. #STD# ";"               : {return 20;}
  2023. #STD# "<"               : {return 21;}
  2024. #STD# "<="              : {return 22;}
  2025. #STD# "<>"              : {return 23;}
  2026. #STD# "="               : {return 24;}
  2027. #STD# ">"               : {return 25;}
  2028. #STD# ">="              : {return 26;}
  2029. #STD# "["               : {return 27;}
  2030. #STD# "]"               : {return 28;}
  2031. #STD# "^"               : {return 29;}
  2032. #STD# "{"               : {return 30;}
  2033. #STD# "|"               : {return 31;}
  2034. #STD# "}"               : {return 32;}
  2035. #STD# "~"               : {return 33;}
  2036. #STD# AND               : {return 34;}
  2037. #STD# ARRAY             : {return 35;}
  2038. #STD# BEGIN             : {return 36;}
  2039. #STD# BY                : {return 37;}
  2040. #STD# CASE              : {return 38;}
  2041. #STD# CONST             : {return 39;}
  2042. #STD# DEFINITION        : {return 40;}
  2043. #STD# DIV               : {return 41;}
  2044. #STD# DO                : {return 42;}
  2045. #STD# ELSE              : {return 43;}
  2046. #STD# ELSIF             : {return 44;}
  2047. #STD# END               : {return 45;}
  2048. #STD# EXIT              : {return 46;}
  2049. #STD# EXPORT            : {return 47;}
  2050. #STD# FOR               : {return 48;}
  2051. #STD# FROM              : {return 49;}
  2052.  
  2053.  
  2054.  
  2055.  
  2056.  
  2057.  
  2058.  
  2059.  
  2060.  
  2061.  
  2062.                                      Rex                                    31
  2063.  
  2064.  
  2065. #STD# IF                : {return 50;}
  2066. #STD# IMPLEMENTATION    : {return 51;}
  2067. #STD# IMPORT            : {return 52;}
  2068. #STD# IN                : {return 53;}
  2069. #STD# LOOP              : {return 54;}
  2070. #STD# MOD               : {return 55;}
  2071. #STD# MODULE            : {return 56;}
  2072. #STD# \NOT              : {return 57;}
  2073. #STD# OF                : {return 58;}
  2074. #STD# OR                : {return 59;}
  2075. #STD# POINTER           : {return 60;}
  2076. #STD# PROCEDURE         : {return 61;}
  2077. #STD# QUALIFIED         : {return 62;}
  2078. #STD# RECORD            : {return 63;}
  2079. #STD# REPEAT            : {return 64;}
  2080. #STD# RETURN            : {return 65;}
  2081. #STD# SET               : {return 66;}
  2082. #STD# THEN              : {return 67;}
  2083. #STD# TO                : {return 68;}
  2084. #STD# TYPE              : {return 69;}
  2085. #STD# UNTIL             : {return 70;}
  2086. #STD# VAR               : {return 71;}
  2087. #STD# WHILE             : {return 72;}
  2088. #STD# WITH              : {return 73;}
  2089. #STD# letter (letter | digit) * : {
  2090.                            ident = MakeIdent (TokenPtr, TokenLength);
  2091.                            return 74;}
  2092.  
  2093.  
  2094.  
  2095.  
  2096.  
  2097.  
  2098.  
  2099.  
  2100.  
  2101.  
  2102.  
  2103.  
  2104.  
  2105.  
  2106.  
  2107.  
  2108.  
  2109.  
  2110.  
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116.  
  2117.  
  2118.  
  2119.  
  2120.  
  2121.  
  2122.  
  2123.  
  2124.  
  2125.  
  2126.  
  2127.                                      Rex                                    32
  2128.  
  2129.  
  2130. Appendix 3: Example Specification of a Modula-2-Scanner in Modula-2
  2131.  
  2132.  
  2133. GLOBAL  {
  2134.    FROM Strings         IMPORT tString          ;
  2135.    FROM StringMem       IMPORT tStringRef       , PutString     ;
  2136.    FROM Idents          IMPORT tIdent           , MakeIdent     ;
  2137.    VAR level            : CARDINAL;
  2138.    PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  2139.       BEGIN
  2140.       END ErrorAttribute;
  2141. }
  2142. LOCAL   {
  2143.    VAR
  2144.       Word              : tString;
  2145.       ident             : tIdent;
  2146.       ref               : tStringRef;
  2147. }
  2148. BEGIN   { level := 0; }
  2149. DEFAULT {
  2150. IO.WriteS (IO.StdOutput, "illegal character: "); yyEcho; IO.WriteNl (IO.StdOutput);
  2151. }
  2152. DEFINE
  2153.    digit        = {0-9}         .
  2154.    letter       = {a-z A-Z}     .
  2155.    cmt          = - {*(\t\n}    .
  2156. START   comment
  2157. RULE
  2158.            "(*"         :- {INC (level); yyStart (comment);}
  2159. #comment#  "*)"         :- {DEC (level); IF level = 0 THEN yyStart (STD); END;}
  2160. #comment#  "(" | "*" | cmt + :- {}
  2161. #STD# digit +           ,
  2162. #STD# digit + / ".."    : {GetWord (Word);
  2163.                            ref := PutString (Word);
  2164.                            RETURN 1;}
  2165. #STD# {0-7} + B         : {GetWord (Word);
  2166.                            ref := PutString (Word);
  2167.                            RETURN 2;}
  2168. #STD# {0-7} + C         : {GetWord (Word);
  2169.                            ref := PutString (Word);
  2170.                            RETURN 3;}
  2171. #STD# digit {0-9 A-F} * H : {
  2172.                            GetWord (Word);
  2173.                            ref := PutString (Word);
  2174.                            RETURN 4;}
  2175. #STD# digit + "." digit * (E {+\-} ? digit +) ? : {
  2176.                            GetWord (Word);
  2177.                            ref := PutString (Word);
  2178.  
  2179.  
  2180.  
  2181.  
  2182.  
  2183.  
  2184.  
  2185.  
  2186.  
  2187.  
  2188.                                      Rex                                    33
  2189.  
  2190.  
  2191.                            RETURN 5;}
  2192. #STD# ' - {\n'} * '     |
  2193.       \" - {\n"} * \"   : {GetWord (Word);
  2194.                            ref := PutString (Word);
  2195.                            RETURN 6;}
  2196. #STD# "#"               : {RETURN 7;}
  2197. #STD# "&"               : {RETURN 8;}
  2198. #STD# "("               : {RETURN 9;}
  2199. #STD# ")"               : {RETURN 10;}
  2200. #STD# "*"               : {RETURN 11;}
  2201. #STD# "+"               : {RETURN 12;}
  2202. #STD# ","               : {RETURN 13;}
  2203. #STD# "-"               : {RETURN 14;}
  2204. #STD# "."               : {RETURN 15;}
  2205. #STD# ".."              : {RETURN 16;}
  2206. #STD# "/"               : {RETURN 17;}
  2207. #STD# ":"               : {RETURN 18;}
  2208. #STD# ":="              : {RETURN 19;}
  2209. #STD# ";"               : {RETURN 20;}
  2210. #STD# "<"               : {RETURN 21;}
  2211. #STD# "<="              : {RETURN 22;}
  2212. #STD# "<>"              : {RETURN 23;}
  2213. #STD# "="               : {RETURN 24;}
  2214. #STD# ">"               : {RETURN 25;}
  2215. #STD# ">="              : {RETURN 26;}
  2216. #STD# "["               : {RETURN 27;}
  2217. #STD# "]"               : {RETURN 28;}
  2218. #STD# "^"               : {RETURN 29;}
  2219. #STD# "{"               : {RETURN 30;}
  2220. #STD# "|"               : {RETURN 31;}
  2221. #STD# "}"               : {RETURN 32;}
  2222. #STD# "~"               : {RETURN 33;}
  2223. #STD# AND               : {RETURN 34;}
  2224. #STD# ARRAY             : {RETURN 35;}
  2225. #STD# BEGIN             : {RETURN 36;}
  2226. #STD# BY                : {RETURN 37;}
  2227. #STD# CASE              : {RETURN 38;}
  2228. #STD# CONST             : {RETURN 39;}
  2229. #STD# DEFINITION        : {RETURN 40;}
  2230. #STD# DIV               : {RETURN 41;}
  2231. #STD# DO                : {RETURN 42;}
  2232. #STD# ELSE              : {RETURN 43;}
  2233. #STD# ELSIF             : {RETURN 44;}
  2234. #STD# END               : {RETURN 45;}
  2235. #STD# EXIT              : {RETURN 46;}
  2236. #STD# EXPORT            : {RETURN 47;}
  2237. #STD# FOR               : {RETURN 48;}
  2238. #STD# FROM              : {RETURN 49;}
  2239. #STD# IF                : {RETURN 50;}
  2240. #STD# IMPLEMENTATION    : {RETURN 51;}
  2241. #STD# IMPORT            : {RETURN 52;}
  2242.  
  2243.  
  2244.  
  2245.  
  2246.  
  2247.  
  2248.  
  2249.  
  2250.  
  2251.  
  2252.                                      Rex                                    34
  2253.  
  2254.  
  2255. #STD# IN                : {RETURN 53;}
  2256. #STD# LOOP              : {RETURN 54;}
  2257. #STD# MOD               : {RETURN 55;}
  2258. #STD# MODULE            : {RETURN 56;}
  2259. #STD# \NOT              : {RETURN 57;}
  2260. #STD# OF                : {RETURN 58;}
  2261. #STD# OR                : {RETURN 59;}
  2262. #STD# POINTER           : {RETURN 60;}
  2263. #STD# PROCEDURE         : {RETURN 61;}
  2264. #STD# QUALIFIED         : {RETURN 62;}
  2265. #STD# RECORD            : {RETURN 63;}
  2266. #STD# REPEAT            : {RETURN 64;}
  2267. #STD# RETURN            : {RETURN 65;}
  2268. #STD# SET               : {RETURN 66;}
  2269. #STD# THEN              : {RETURN 67;}
  2270. #STD# TO                : {RETURN 68;}
  2271. #STD# TYPE              : {RETURN 69;}
  2272. #STD# UNTIL             : {RETURN 70;}
  2273. #STD# VAR               : {RETURN 71;}
  2274. #STD# WHILE             : {RETURN 72;}
  2275. #STD# WITH              : {RETURN 73;}
  2276. #STD# letter (letter | digit) * : {
  2277.                            GetWord (Word);
  2278.                            ident := MakeIdent (Word);
  2279.                            RETURN 74;}
  2280.  
  2281.  
  2282.  
  2283.  
  2284.  
  2285.  
  2286.  
  2287.  
  2288.  
  2289.  
  2290.  
  2291.  
  2292.  
  2293.  
  2294.  
  2295.  
  2296.  
  2297.  
  2298.  
  2299.  
  2300.  
  2301.  
  2302.  
  2303.  
  2304.  
  2305.  
  2306.  
  2307.  
  2308.  
  2309.  
  2310.  
  2311.  
  2312.  
  2313.  
  2314.  
  2315.  
  2316.  
  2317.                                      Rex                                    35
  2318.  
  2319.  
  2320. Appendix 4: Example Specification of a Scanner for Rex
  2321.  
  2322.  
  2323. EXPORT  {
  2324.  
  2325. FROM Idents     IMPORT tIdent   ;
  2326. FROM StringMem  IMPORT tStringRef;
  2327. FROM Texts      IMPORT tText    ;
  2328. FROM Positions  IMPORT tPosition;
  2329.  
  2330. TYPE
  2331.    tScanAttribute       = RECORD
  2332.               Position  : tPosition     ;
  2333.          CASE : INTEGER OF
  2334.          | 1: Ident     : tIdent        ;
  2335.          | 2: Number    : SHORTCARD     ;
  2336.          | 3: String    : tStringRef    ;
  2337.          | 4: Ch        : CHAR          ;
  2338.          | 5: Text      : tText         ;
  2339.          END;
  2340.       END;
  2341.  
  2342. PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  2343. }
  2344.  
  2345. GLOBAL  {
  2346.  
  2347. FROM SYSTEM     IMPORT ADDRESS;
  2348. FROM Strings    IMPORT tString, Concatenate, Char, SubString,
  2349.                         StringToInt, AssignEmpty, Length;
  2350. FROM Texts      IMPORT MakeText, Append;
  2351. FROM StringMem  IMPORT tStringRef, PutString;
  2352. FROM Idents     IMPORT tIdent, MakeIdent, NoIdent;
  2353. FROM Errors     IMPORT ErrorMessage, Error;
  2354. FROM ScanGen    IMPORT Language, tLanguage;
  2355. FROM Positions  IMPORT tPosition;
  2356.  
  2357. CONST
  2358.    SymIdent             = 1     ;
  2359.    SymNumber            = 2     ;
  2360.    SymString            = 3     ;
  2361.    SymChar              = 4     ;
  2362.    SymTargetcode        = 5     ;
  2363.    SymScanner           = 37    ;
  2364.    SymExport            = 32    ;
  2365.    SymGlobal            = 6     ;
  2366.    SymLocal             = 31    ;
  2367.    SymBegin             = 7     ;
  2368.    SymClose             = 8     ;
  2369.    SymEof               = 34    ;
  2370.    SymDefault           = 36    ;
  2371.    SymDefine            = 9     ;
  2372.    SymStart             = 10    ;
  2373.  
  2374.  
  2375.  
  2376.  
  2377.  
  2378.  
  2379.  
  2380.  
  2381.  
  2382.  
  2383.                                      Rex                                    36
  2384.  
  2385.  
  2386.    SymRules             = 11    ;
  2387.    SymNot               = 30    ;
  2388.    SymDot               = 12    ;
  2389.    SymComma             = 13    ;
  2390.    SymEqual             = 14    ;
  2391.    SymColon             = 15    ;
  2392.    SymColonMinus        = 35    ;
  2393.    SymNrSign            = 33    ;
  2394.    SymSlash             = 16    ;
  2395.    SymBar               = 17    ;
  2396.    SymPlus              = 18    ;
  2397.    SymMinus             = 19    ;
  2398.    SymAsterisk          = 20    ;
  2399.    SymQuestion          = 21    ;
  2400.    SymLParen            = 22    ;
  2401.    SymRParen            = 23    ;
  2402.    SymLBracket          = 24    ;
  2403.    SymRBracket          = 25    ;
  2404.    SymLBrace            = 26    ;
  2405.    SymRBrace            = 27    ;
  2406.    SymLess              = 28    ;
  2407.    SymGreater           = 29    ;
  2408.  
  2409.    BraceMissing         = 13    ;
  2410.    UnclosedComment      = 14    ;
  2411.    UnclosedString       = 16    ;
  2412.  
  2413. VAR
  2414.    level        : INTEGER       ;
  2415.    string       : tString       ;
  2416.    NoString     : tStringRef    ;
  2417.    Position     : tPosition     ;
  2418.  
  2419. PROCEDURE ErrorAttribute (Token: INTEGER; VAR Attribute: tScanAttribute);
  2420.    BEGIN
  2421.       CASE Token OF
  2422.       |  SymIdent       : Attribute.Ident  := NoIdent;
  2423.       |  SymNumber      : Attribute.Number := 0;
  2424.       |  SymString      : Attribute.String := NoString;
  2425.       |  SymChar        : Attribute.Ch     := '?';
  2426.       |  SymTargetcode  : MakeText (Attribute.Text);
  2427.       ELSE
  2428.       END;
  2429.    END ErrorAttribute;
  2430. }
  2431.  
  2432. LOCAL   { VAR TargetCode, String, Word: tString; PrevState: SHORTCARD; }
  2433.  
  2434. BEGIN   {
  2435.    level := 0;
  2436.    AssignEmpty (string);
  2437.    NoString := PutString (string);
  2438. }
  2439.  
  2440.  
  2441.  
  2442.  
  2443.  
  2444.  
  2445.  
  2446.  
  2447.  
  2448.  
  2449.                                      Rex                                    37
  2450.  
  2451.  
  2452. EOF     {
  2453.    CASE yyStartState OF
  2454.    | targetcode ,
  2455.      set        : ErrorMessage (BraceMissing    , Error, Attribute.Position);
  2456.    | comment    : ErrorMessage (UnclosedComment , Error, Attribute.Position);
  2457.    | CStr1, CStr2,
  2458.      Str1, Str2 : ErrorMessage (UnclosedString  , Error, Attribute.Position);
  2459.    ELSE
  2460.    END;
  2461.    yyStart (STD);
  2462. }
  2463.  
  2464. DEFINE
  2465.    letter       = {A-Z a-z}     .
  2466.    digit        = {0-9}         .
  2467.    string       = - {"\n}       .
  2468.    cmtch        = - {*\t\n}     .
  2469.    code         = - {{\}\t\n\\'"} .
  2470.    StrCh1       = - {'\t\n}     .
  2471.    StrCh2       = - {"\t\n}     .
  2472.    CStrCh1      = - {'\t\n\\}   .
  2473.    CStrCh2      = - {"\t\n\\}   .
  2474.  
  2475. START targetcode, set, rules, comment, Str1, Str2, CStr1, CStr2
  2476.  
  2477. RULES
  2478.  
  2479. #targetcode#    "{"     : {
  2480.                            IF level = 0 THEN
  2481.                               MakeText (Attribute.Text);
  2482.                               AssignEmpty (TargetCode);
  2483.                               Position := Attribute.Position;
  2484.                            ELSE
  2485.                               GetWord (Word);
  2486.                               Concatenate (TargetCode, Word);
  2487.                            END;
  2488.                            INC (level);
  2489.                         }
  2490.  
  2491. #targetcode#    "}"     :- {
  2492.                            DEC (level);
  2493.                            IF level = 0 THEN
  2494.                               yyStart (PrevState);
  2495.                               Append (Attribute.Text, TargetCode);
  2496.                               Attribute.Position := Position;
  2497.                               RETURN SymTargetcode;
  2498.                            ELSE
  2499.                               GetWord (Word);
  2500.                               Concatenate (TargetCode, Word);
  2501.                            END;
  2502.                         }
  2503.  
  2504. #targetcode#    code +  :- {
  2505.  
  2506.  
  2507.  
  2508.  
  2509.  
  2510.  
  2511.  
  2512.  
  2513.  
  2514.  
  2515.                                      Rex                                    38
  2516.  
  2517.  
  2518.                            IF level > 0 THEN
  2519.                               GetWord (Word);
  2520.                               Concatenate (TargetCode, Word);
  2521.                            END;
  2522.                         }
  2523.  
  2524. #targetcode#    \t      :- {
  2525.                            IF level > 0 THEN
  2526.                               Strings.Append (TargetCode, 11C);
  2527.                            END;
  2528.                            yyTab;
  2529.                         }
  2530.  
  2531. #targetcode#    \n      :- {
  2532.                            IF level > 0 THEN
  2533.                               Append (Attribute.Text, TargetCode);
  2534.                               AssignEmpty (TargetCode);
  2535.                            END;
  2536.                            yyEol (0);
  2537.                         }
  2538.  
  2539. #targetcode#    \\ ANY  :- {
  2540.                            IF level > 0 THEN
  2541.                               GetWord (Word);
  2542.                               Strings.Append (TargetCode, Char (Word, 2));
  2543.                            END;
  2544.                         }
  2545.  
  2546. #targetcode#    \\      :- {
  2547.                            IF level > 0 THEN
  2548.                               Strings.Append (TargetCode, '\');
  2549.                            END;
  2550.                         }
  2551.  
  2552. #targetcode#    '       : {
  2553.                            GetWord (String);
  2554.                            IF Language = C
  2555.                            THEN yyStart (CStr1);
  2556.                            ELSE yyStart (Str1);
  2557.                            END;
  2558.                         }
  2559.  
  2560. #targetcode#    \"      : {
  2561.                            GetWord (String);
  2562.                            IF Language = C
  2563.                            THEN yyStart (CStr2);
  2564.                            ELSE yyStart (Str2);
  2565.                            END;
  2566.                         }
  2567.  
  2568. #Str1#  StrCh1 +        ,
  2569. #Str2#  StrCh2 +        ,
  2570. #CStr1# CStrCh1 + | \\ ANY ? ,
  2571.  
  2572.  
  2573.  
  2574.  
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.                                      Rex                                    39
  2582.  
  2583.  
  2584. #CStr2# CStrCh2 + | \\ ANY ? :- {GetWord (Word); Concatenate (String, Word);}
  2585.  
  2586. #CStr1# \\ \n           ,
  2587. #CStr2# \\ \n           :- {GetWord (Word); Concatenate (String, Word); yyEol (0);}
  2588.  
  2589. #Str1, CStr1# '         ,
  2590. #Str2, CStr2# \"        :- {Strings.Append (String, Char (String, 1));
  2591.                             yyPrevious; Concatenate (TargetCode, String);
  2592.                         }
  2593.  
  2594. #Str1, Str2, CStr1, CStr2# \t :- {Strings.Append (String, 11C); yyTab;}
  2595.  
  2596. #Str1, Str2, CStr1, CStr2# \n :- {
  2597.                             ErrorMessage (UnclosedString, Error, Attribute.Position);
  2598.                             Strings.Append (String, Char (String, 1));
  2599.                             yyEol (0); yyPrevious; Concatenate (TargetCode, String);
  2600.                         }
  2601.  
  2602. #STD, rules#    "/*"    :- {yyStart (comment)   ;}
  2603. #comment#       "*" | cmtch +   :- {}
  2604. #comment#       "*/"    :- {yyPrevious          ;}
  2605.  
  2606. #STD#           EXPORT  : {PrevState := STD; yyStart (targetcode);
  2607.                            RETURN SymExport     ;}
  2608. #STD#           GLOBAL  : {PrevState := STD; yyStart (targetcode);
  2609.                            RETURN SymGlobal     ;}
  2610. #STD#           LOCAL   : {PrevState := STD; yyStart (targetcode);
  2611.                            RETURN SymLocal      ;}
  2612. #STD#           BEGIN   : {PrevState := STD; yyStart (targetcode);
  2613.                            RETURN SymBegin      ;}
  2614. #STD#           CLOSE   : {PrevState := STD; yyStart (targetcode);
  2615.                            RETURN SymClose      ;}
  2616. #STD#           DEFAULT : {PrevState := STD; yyStart (targetcode);
  2617.                            RETURN SymDefault    ;}
  2618. #STD#           EOF     : {PrevState := STD; yyStart (targetcode);
  2619.                            RETURN SymEof        ;}
  2620. #STD#           SCANNER : {RETURN SymScanner    ;}
  2621. #STD#           DEFINE  : {RETURN SymDefine     ;}
  2622. #STD#           START   : {RETURN SymStart      ;}
  2623. #STD#           RULE S ?: {yyStart (rules);     RETURN SymRules         ;}
  2624. #rules#         \NOT    : {RETURN SymNot        ;}
  2625.  
  2626. #STD, rules#    letter (letter | digit | _) * : {
  2627.                            GetWord (Word);
  2628.                            Attribute.Ident  := MakeIdent (Word);
  2629.                            RETURN SymIdent;
  2630.                         }
  2631.  
  2632. #STD, rules#    digit + : {
  2633.                            GetWord (Word);
  2634.                            Attribute.Number := StringToInt (Word);
  2635.                            RETURN SymNumber;
  2636.                         }
  2637.  
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.  
  2644.  
  2645.  
  2646.  
  2647.                                      Rex                                    40
  2648.  
  2649.  
  2650. #STD, rules#    \" string * \" : {
  2651.                            GetWord (Word);
  2652.                            SubString (Word, 2, Length (Word) - 1, TargetCode);
  2653.                            Attribute.String := PutString (TargetCode);
  2654.                            RETURN SymString;
  2655.                         }
  2656.  
  2657. #STD#           "."     : {RETURN SymDot        ;}
  2658. #STD#           "="     : {RETURN SymEqual      ;}
  2659. #STD, set#      "}"     : {yyPrevious;          RETURN SymRBrace        ;}
  2660. #STD, set, rules# "-"   : {RETURN SymMinus      ;}
  2661. #STD, rules#    ","     : {RETURN SymComma      ;}
  2662. #STD, rules#    "|"     : {RETURN SymBar        ;}
  2663. #STD, rules#    "+"     : {RETURN SymPlus       ;}
  2664. #STD, rules#    "*"     : {RETURN SymAsterisk   ;}
  2665. #STD, rules#    "?"     : {RETURN SymQuestion   ;}
  2666. #STD, rules#    "("     : {RETURN SymLParen     ;}
  2667. #STD, rules#    ")"     : {RETURN SymRParen     ;}
  2668. #STD, rules#    "["     : {RETURN SymLBracket   ;}
  2669. #STD, rules#    "]"     : {RETURN SymRBracket   ;}
  2670. #STD, rules#    "{"     : {yyStart (set);       RETURN SymLBrace        ;}
  2671. #rules#         "#"     : {RETURN SymNrSign     ;}
  2672. #rules#         "/"     : {RETURN SymSlash      ;}
  2673. #rules#         "<"     : {RETURN SymLess       ;}
  2674. #rules#         ">"     : {RETURN SymGreater    ;}
  2675. #rules#         ":"     : {PrevState := rules; yyStart (targetcode);
  2676.                            RETURN SymColon      ;}
  2677. #rules#         ":-"    : {PrevState := rules; yyStart (targetcode);
  2678.                            RETURN SymColonMinus ;}
  2679.  
  2680. #STD, set, rules# \\ n  : {Attribute.Ch := 012C; RETURN SymChar;}
  2681. #STD, set, rules# \\ t  : {Attribute.Ch := 011C; RETURN SymChar;}
  2682. #STD, set, rules# \\ v  : {Attribute.Ch := 013C; RETURN SymChar;}
  2683. #STD, set, rules# \\ b  : {Attribute.Ch := 010C; RETURN SymChar;}
  2684. #STD, set, rules# \\ r  : {Attribute.Ch := 015C; RETURN SymChar;}
  2685. #STD, set, rules# \\ f  : {Attribute.Ch := 014C; RETURN SymChar;}
  2686.  
  2687. #STD, set, rules# \\ digit + : {
  2688.                            GetWord (Word);
  2689.                            SubString (Word, 2, Length (Word), TargetCode);
  2690.                            Attribute.Ch := CHR (CARDINAL (StringToInt (TargetCode)));
  2691.                            RETURN SymChar;
  2692.                         }
  2693.  
  2694. #STD, set, rules# \\ ANY : {
  2695.                            GetWord (Word);
  2696.                            Attribute.Ch := Char (Word, 2);
  2697.                            RETURN SymChar;
  2698.                         }
  2699.  
  2700. #STD, set, rules# - {\t\n\ \f\r} : {
  2701.                            GetWord (Word);
  2702.                            Attribute.Ch := Char (Word, 1);
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.  
  2713.                                      Rex                                    41
  2714.  
  2715.  
  2716.                            RETURN SymChar;
  2717.                         }
  2718.  
  2719. \f                      :- {}
  2720. \r                      :- {}
  2721.  
  2722.  
  2723. References
  2724.  
  2725. [ASU86]
  2726.      A. V. Aho, R. Sethi and J. D. Ullman, Compilers: Principles,  Techniques,
  2727.      and Tools, Addison Wesley, Reading, MA, 1986.
  2728.  
  2729. [Gro87]
  2730.      J. Grosch, Reusable Software - A Collection of  Modula-Modules,  Compiler
  2731.      Generation   Report  No.  4,  GMD  Forschungsstelle  an  der  Universitat
  2732.      Karlsruhe, Sep. 1987.
  2733.  
  2734. [Gro89]
  2735.      J. Grosch, Efficient Generation of Lexical Analysers, Software-Practice &
  2736.      Experience 19, 11 (Nov. 1989), 1089-1103.
  2737.  
  2738. [Les75]
  2739.      M. E. Lesk,  LEX  -  A  Lexical  Analyzer  Generator,  Computing  Science
  2740.      Technical Report 39, Bell Telephone Laboratories, Murray Hill, NJ, 1975.
  2741.  
  2742.  
  2743.  
  2744.  
  2745.  
  2746.  
  2747.  
  2748.  
  2749.  
  2750.  
  2751.  
  2752.  
  2753.  
  2754.  
  2755.  
  2756.  
  2757.  
  2758.  
  2759.  
  2760.  
  2761.  
  2762.  
  2763.  
  2764.  
  2765.  
  2766.  
  2767.  
  2768.  
  2769.  
  2770.  
  2771.  
  2772.  
  2773.  
  2774.  
  2775.  
  2776.  
  2777.  
  2778.                                      Rex                                     1
  2779.  
  2780.  
  2781. Contents
  2782.  
  2783. 1.      Introduction ....................................................    1
  2784. 2.      Overview ........................................................    1
  2785. 3.      Specification Language ..........................................    2
  2786. 3.1.    Lexical Conventions .............................................    2
  2787. 3.2.    Regular Expressions .............................................    4
  2788. 3.3.    Ambiguous Specifications ........................................    7
  2789. 3.4.    Definitions .....................................................    8
  2790. 3.5.    Start States ....................................................    8
  2791. 3.6.    Scanner Name ....................................................    9
  2792. 3.7.    Target Code .....................................................    9
  2793. 3.8.    Source Position .................................................   12
  2794. 4.      Predefined Items ................................................   12
  2795. 4.1.    Definitions .....................................................   12
  2796. 4.2.    Start States ....................................................   13
  2797. 4.3.    Rules ...........................................................   13
  2798. 4.4.    Action Statements ...............................................   13
  2799. 5.      Interface of the Generated Scanners .............................   14
  2800. 5.1.    C ...............................................................   14
  2801. 5.1.1.  Scanner Interface ...............................................   14
  2802. 5.1.2.  Source Interface ................................................   16
  2803. 5.1.3.  Scanner Driver ..................................................   17
  2804. 5.2.    Modula-2 ........................................................   18
  2805. 5.2.1.  Scanner Interface ...............................................   18
  2806. 5.2.2.  Source Interface ................................................   20
  2807. 5.2.3.  Scanner Driver ..................................................   21
  2808. 6.      Usage ...........................................................   22
  2809. 7.      Implementation ..................................................   24
  2810. 8.      Differences to LEX ..............................................   25
  2811.         Appendix 1: Syntax of the Specification Language ................   27
  2812.         Appendix 2: Example Specification of a Modula-2-Scanner  in  C
  2813.      ....................................................................   29
  2814.         Appendix 3: Example Specification  of  a  Modula-2-Scanner  in
  2815.      Modula-2 ...........................................................   32
  2816.         Appendix 4: Example Specification of a Scanner for Rex ..........   35
  2817.         References ......................................................   41
  2818.  
  2819.  
  2820.  
  2821.  
  2822.  
  2823.  
  2824.  
  2825.  
  2826.  
  2827.  
  2828.  
  2829.  
  2830.  
  2831.  
  2832.  
  2833.  
  2834.  
  2835.  
  2836.  
  2837.  
  2838.  
  2839.